package ipc

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"gitee.com/watertreestar/octans-device-sdk/internal"
	"gitee.com/watertreestar/octans-device-sdk/log"
	"gitee.com/watertreestar/octans-device-sdk/shadow"
	"github.com/jasonlvhit/gocron"
	"github.com/loozhengyuan/hikvision-sdk/hikvision"
	"github.com/quocson95/go-onvif"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type onvifDevice struct {
	sn       string
	xaddr    string
	username string
	password string
}

type SearchedDevice struct {
	ID    string `json:"id"`
	Name  string `json:"version"`
	XAddr string `json:"xaddr"`
	Host  string `json:"host"`
}

type InputProxyChannel struct {
	XmlName                   xml.Name                  `xml:"InputProxyChannel"`
	ID                        string                    `xml:"id"`
	Name                      string                    `xml:"name"`
	SourceInputPortDescriptor SourceInputPortDescriptor `xml:"sourceInputPortDescriptor"`
}

type SourceInputPortDescriptor struct {
	ID                   string `json:"id"`
	Name                 string `json:"name"`
	AdminProtocol        string `xml:"adminProtocol" json:"admin-protocol"`
	AddressingFormatType string `xml:"addressingFormatType" json:"addressing_format_type"`
	IPAddress            string `xml:"ipAddress,omitempty" json:"ip_address"`
	ManagePortNo         int    `xml:"managePortNo" json:"manage_port_no"`
	SrcInputPort         string `xml:"srcInputPort"`
	UserName             string `xml:"userName" json:"user_name"`
	Password             string `xml:"password" json:"password"`
	SerialNumber         string `xml:"serialNumber" json:"serial_number"`
}

func init() {
	flag.Parse()
}

// Connector 使用SIAPI协议和海康威视NVR通信,使用onvif和ipc通信
type Connector struct {
	devices []onvifDevice
	logger  log.Logger
	s       *gocron.Scheduler
}

func NewConnector(logger log.Logger) *Connector {
	return &Connector{
		logger: logger,
	}
}

func (c *Connector) Initialize() error {
	c.s = gocron.NewScheduler()
	c.s.Start()
	go c.pingTick()
	return nil
}

// Discovery 发现ipc设备
func (c *Connector) Discovery() (devices []SearchedDevice, err error) {
	ifaces, err := internal.FilterInterfaces(true)
	c.logger.Info("starting to discovery ipc device, net interface count: %c", len(ifaces))
	if err != nil {
		return nil, err
	}

	var onvifDevices []onvif.Device
	for _, iface := range ifaces {
		devices, err := onvif.StartDiscovery(iface.Name, time.Second*1)
		if err != nil {
			continue
		}
		onvifDevices = append(onvifDevices, devices...)
	}
	var sd []SearchedDevice
	for _, d := range onvifDevices {
		s := SearchedDevice{
			ID:    d.ID,
			Name:  d.Name,
			Host:  strings.Split(d.XAddr, "/")[2],
			XAddr: d.XAddr,
		}
		sd = append(sd, s)
	}
	return sd, nil
}

func (c *Connector) GetStreamUrl(xaddr, username, password string) (url string, err error) {
	od := onvif.Device{
		XAddr:    xaddr,
		User:     username,
		Password: password,
	}
	profiles, err := od.GetProfiles()
	if err != nil {
		return "", err
	}
	if len(profiles) < 1 {
		return "", errors.New("profiles < 1")
	}
	uri, err := od.GetStreamURI(profiles[0].Token, "RTSP")
	if err != nil {
		return "", err
	}
	return uri.URI, nil
}

func (c *Connector) Destroy() error {
	return nil
}

// AddDevice 添加设备，sn为不重复的任意值
// xaddr onvif地址
// username onvif用户名
// password onvif密码
func (c *Connector) AddDevice(sn, xaddr, username, password string) error {
	if len(strings.TrimSpace(sn)) == 0 {
		return errors.New("device sn must not be empty")
	}
	if err := shadow.Of().AddDevice(sn, time.Minute*3); err != nil {
		return err
	}
	c.devices = append(c.devices, onvifDevice{
		xaddr:    xaddr,
		username: username,
		password: password,
		sn:       sn,
	})
	go c.probeStatus()
	return nil
}

func (c *Connector) RemoveDevice(sn string) error {
	if err := shadow.Of().RemoveDevice(sn); err != nil {
		return err
	}
	devices := c.devices
	var filter []onvifDevice
	for _, d := range devices {
		if d.sn != sn {
			filter = append(filter, d)
		}
	}
	c.devices = filter
	return nil
}

func (c *Connector) probeStatus() {
	for _, d := range c.devices {
		od := onvif.Device{
			XAddr:    d.xaddr,
			User:     d.username,
			Password: d.password,
		}
		_, err := od.GetCapabilities()
		if err == nil {
			_ = shadow.Of().RefreshUpdateAt(d.sn)
		}
	}
}

// 获取状态
func (c *Connector) pingTick() {
	if err := c.s.Every(30).Seconds().Do(c.probeStatus); err != nil {
		c.logger.Error("%s\n", "start ipc status check error")
	}
}

func currentChanNo(nvrclient *hikvision.Client) (no int, err error) {
	u, _ := url.Parse(nvrclient.BaseURL + "/ISAPI/System/workingstatus?format=json")
	st, err := nvrclient.Get(u)
	if err != nil {
		return 0, err
	}
	var status struct {
		WorkingStatus struct {
			ChanStatus []interface{} `json:"ChanStatus"`
		} `json:"WorkingStatus"`
	}
	_ = json.Unmarshal(st, &status)
	return len(status.WorkingStatus.ChanStatus), nil
}

// RemoveChannel 从NVR中移除通道 todo
func (c *Connector) RemoveChannel() error {
	return nil
}

// AddChannel 添加IPC设备到某一个通道 todo
func (c *Connector) AddChannel() error {
	return nil
}

func post(nvrclient *hikvision.Client, u url.URL, data []byte, contentType string) ([]byte, error) {
	b := bytes.NewBuffer(data)
	req, err := http.NewRequest("GET", u.String(), b)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	return nvrclient.Do(req)
}
